﻿//========================================================= 
/**@file CCID_CmdDriver.h
 * @brief CCID命令驱动
 * 
 * @date 2017-04-02   16:02:35
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_CCID_CMDDRIVER_H_
#define _LIBZHOUYB_CCID_CMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// CCID驱动
class CCID_CmdDriver : public CommonCmdDriver, public InterruptBehavior
{
protected:
    Ref<ITransceiveTrans> _pBaseIC;
    Ref<IICCardDevice> _pIC;
    CCID_Device _cciddev;
public:
    CCID_CmdDriver() : CommonCmdDriver()
    {
        _errGetter.Add(_cciddev);
        _logSetter.select(_cciddev);

        _pBaseIC = _cciddev;
        _pIC = _cciddev;

        _RegisteCMD(CCID_CmdDriver, EnumDevice);
        _RegisteCMD(CCID_CmdDriver, IsExist);
        _RegisteCMD(CCID_CmdDriver, IsCardPresent);

        _RegisteInterfaceCMD(CCID_CmdDriver, IICCardDevice);
        _RegisteInterfaceCMD(CCID_CmdDriver, ITransceiveTrans);
        _RegisteIICCardCMD(CCID_CmdDriver);
        _RegisteCancelCMD(CCID_CmdDriver);
    }
    LC_CMD_INTERFACE_GETTER(IICCardDevice, _pIC);
    LC_CMD_INTERFACE_GETTER(ITransceiveTrans, _pBaseIC);
    /// IC卡命令交互接口
    LC_CMD_ICCARDTRANSMIT(_pIC);
    /// 中断
    LC_CMD_CANCEL(*this);
    /**
     * @brief 枚举当前连接的设备名称
     * @date 2017-04-02 16:22
     *
     * @param Name : string [default:""] 需要匹配的部分名称
     * 
     * @retval Name : string 枚举到的设备名称
     * @retval Count : size_t 枚举到的设备数目
     */
    LC_CMD_METHOD(EnumDevice)
    {
        list_t<string> devlist;
        _cciddev.EnumDevice(devlist);

        string name = arg["Name"].To<string>("");
        list_t<string>::iterator itr;
        size_t count = 0;
        ByteArray sName(name.c_str(), name.length());
        for(itr = devlist.begin();itr != devlist.end(); ++itr)
        {
            if(!sName.IsEmpty())
            {
                if(!StringConvert::Contains(ByteArray(itr->c_str(), itr->length()), sName))
                    continue;
            }
            rlt.Put("Name", (*itr));
            ++count;
        }
        rlt.Put("Count", ArgConvert::ToString(count));
        return true;
    }
    /**
     * @brief 返回指定名称的设备是否有卡
     * @date 2017-04-02 16:52
     * 
     * @param [in] Name : string [default:NULL] 需要判断卡片的读卡器名称
     *
     * @retval StateCode : uint 状态位
     * @retval State : string 状态字符串描述
     * @retval IsPresent : bool 是否有卡
     */
    LC_CMD_METHOD(IsCardPresent)
    {
        DWORD currentState = SCARD_STATE_EMPTY;
        DWORD eventState = SCARD_STATE_EMPTY;

        string name = arg["Name"].To<string>();
        if(!_cciddev.SCardReaderState(currentState, eventState, name.c_str()))
            return false;
        rlt.Put("StateCode", ArgConvert::ToString(eventState));
        rlt.Put("State", CCID_Device::StateToString(eventState));
        bool isPresent = CCID_Device::IsState(eventState, SCARD_STATE_PRESENT);
        rlt.Put("IsPresent", ArgConvert::ToString(isPresent));
        return true;
    }
    /**
     * @brief 返回指定名称的设备
     * @date 2017-04-02 16:32
     * 
     * @param [in] Name : string 需要判断的设备名称(部分匹配)
     */
    LC_CMD_METHOD(IsExist)
    {
        string name = arg["Name"].To<string>();
        if(CCID_DeviceHelper::IsExist(name.c_str()) != DevHelper::EnumSUCCESS)
            return false;
        return true;
    }
    /**
     * @brief 等待放卡
     * @date 2017-04-02 16:20
     * 
     * @param [in] Name : string 需要上电的设备名称(部分匹配)
     * @param [in] Timeout : uint [default:DEV_WAIT_TIMEOUT] 等待上电的超时时间(ms)
     * @param [in] Interval : uint [default:DEV_OPERATOR_INTERVAL] 轮询时的间隔时间(ms)
     * 
     * @retval Name : string 最后实际上电的设备名称
     * @retval ATR : hex 上电后的卡片ATR
     */
    LC_CMD_METHOD(PowerOn)
    {
        string name = arg["Name"].To<string>();
        ByteBuilder atr(8);
        list_t<string> devlist;
        _cciddev.EnumDevice(devlist);

        Timer timer;
        uint timeoutMs = arg["Timeout"].To<uint>(DEV_WAIT_TIMEOUT);
        uint intervalMs = arg["Interval"].To<uint>(DEV_OPERATOR_INTERVAL);
        while(timer.Elapsed() < timeoutMs)
        {
            if(InterruptBehavior::Implement(*this))
            {
                ResetErr();
                _logErr(DeviceError::OperatorInterruptErr);
                return false;
            }

            if(CCID_DeviceHelper::PowerOn(_cciddev, name.c_str(), &atr, SIZE_EOF, &devlist) == DevHelper::EnumSUCCESS)
            {
                rlt.Put("Name", _cciddev.GetReader());

                ByteBuilder tmp(16);
                ByteConvert::ToAscii(atr, tmp);
                rlt.Put("ATR", tmp.GetString());
                return true;
            }
            Timer::Wait(intervalMs);
        }
        ResetErr();
        _logErr(DeviceError::WaitTimeOutErr, "等待放卡超时");
        return false;
    }
    /// 是否有卡片已经激活
    LC_CMD_METHOD(IsActive)
    {
        return !(_pIC.IsNull());
    }
    /// 卡片下电
    LC_CMD_METHOD(PowerOff)
    {
        if(_pIC.IsNull())
            return false;

        _pIC->PowerOff();
        _pIC.Free();
        return true;
    }
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_CCID_CMDDRIVER_H_
//========================================================= 